package org.crud4j.core.defprovider;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.crud4j.core.CrudBeanDef;

/**
 * Factory of providers.
 */
public class CrudBeanDefFactory {

	private static Logger log = Logger.getLogger(CrudBeanDefFactory.class);

	/**
	 * Definition providers
	 */
	private static Collection<CrudBeanDefProvider> providers = new ArrayList<CrudBeanDefProvider>();

	static {
		// Add default provider
		providers.add(new AnnCrudDefProvider());
	}

	/**
	 * Adds a custom provider to the factory
	 * 
	 * @param provider
	 */
	public static void registerProvider(CrudBeanDefProvider provider) {
		if (!providers.contains(provider)) {
			providers.add(provider);
		} else {
			log.warn("trying to register an already registered provider "
					+ provider.getClass().getName());
		}
	}

	/**
	 * Definitions cache
	 */
	private static Map<Class, CrudBeanDef> cache = new HashMap<Class, CrudBeanDef>();

	/**
	 * Creates the definition for the given type
	 * 
	 * @param type
	 * @return
	 */
	public static CrudBeanDef getDefinition(Class type) {
		if (cache.containsKey(type)) {
			return cache.get(type);
		}
		synchronized (cache) {
			CrudBeanDef def = new CrudBeanDef();
			def.setType(type);
			for (CrudBeanDefProvider provider : providers) {
				provider.updateDef(type, def);
			}
			cache.put(type, def);
			return def;
		}
	}

}
